1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect.testing.testers;
18  
19  import static com.google.common.collect.testing.features.CollectionSize.ZERO;
20  import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
21  import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
22  import static com.google.common.collect.testing.features.MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION;
23  import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
24  import static java.util.Collections.singletonList;
25  
26  import com.google.common.annotations.GwtCompatible;
27  import com.google.common.collect.testing.AbstractMapTester;
28  import com.google.common.collect.testing.MinimalCollection;
29  import com.google.common.collect.testing.features.CollectionSize;
30  import com.google.common.collect.testing.features.MapFeature;
31  
32  import java.util.Collections;
33  import java.util.ConcurrentModificationException;
34  import java.util.Iterator;
35  import java.util.LinkedHashMap;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Map.Entry;
39  
40  /**
41   * A generic JUnit test which tests {@code putAll} operations on a map. Can't be
42   * invoked directly; please see
43   * {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
44   *
45   * @author Chris Povirk
46   * @author Kevin Bourrillion
47   */
48  @SuppressWarnings("unchecked") // too many "unchecked generic array creations"
49  @GwtCompatible(emulated = true)
50  public class MapPutAllTester<K, V> extends AbstractMapTester<K, V> {
51    private List<Entry<K, V>> containsNullKey;
52    private List<Entry<K, V>> containsNullValue;
53  
54    @Override public void setUp() throws Exception {
55      super.setUp();
56      containsNullKey = singletonList(entry(null, samples.e3.getValue()));
57      containsNullValue = singletonList(entry(samples.e3.getKey(), null));
58    }
59  
60    @MapFeature.Require(SUPPORTS_PUT)
61    public void testPutAll_supportedNothing() {
62      getMap().putAll(emptyMap());
63      expectUnchanged();
64    }
65  
66    @MapFeature.Require(absent = SUPPORTS_PUT)
67    public void testPutAll_unsupportedNothing() {
68      try {
69        getMap().putAll(emptyMap());
70      } catch (UnsupportedOperationException tolerated) {
71      }
72      expectUnchanged();
73    }
74  
75    @MapFeature.Require(SUPPORTS_PUT)
76    public void testPutAll_supportedNonePresent() {
77      putAll(createDisjointCollection());
78      expectAdded(samples.e3, samples.e4);
79    }
80  
81    @MapFeature.Require(absent = SUPPORTS_PUT)
82    public void testPutAll_unsupportedNonePresent() {
83      try {
84        putAll(createDisjointCollection());
85        fail("putAll(nonePresent) should throw");
86      } catch (UnsupportedOperationException expected) {
87      }
88      expectUnchanged();
89      expectMissing(samples.e3, samples.e4);
90    }
91  
92    @MapFeature.Require(SUPPORTS_PUT)
93    @CollectionSize.Require(absent = ZERO)
94    public void testPutAll_supportedSomePresent() {
95      putAll(MinimalCollection.of(samples.e3, samples.e0));
96      expectAdded(samples.e3);
97    }
98  
99    @MapFeature.Require({ FAILS_FAST_ON_CONCURRENT_MODIFICATION,
100       SUPPORTS_PUT })
101   @CollectionSize.Require(absent = ZERO)
102   public void testPutAllSomePresentConcurrentWithEntrySetIteration() {
103     try {
104       Iterator<Entry<K, V>> iterator = getMap().entrySet().iterator();
105       putAll(MinimalCollection.of(samples.e3, samples.e0));
106       iterator.next();
107       fail("Expected ConcurrentModificationException");
108     } catch (ConcurrentModificationException expected) {
109       // success
110     }
111   }
112 
113   @MapFeature.Require(absent = SUPPORTS_PUT)
114   @CollectionSize.Require(absent = ZERO)
115   public void testPutAll_unsupportedSomePresent() {
116     try {
117       putAll(MinimalCollection.of(samples.e3, samples.e0));
118       fail("putAll(somePresent) should throw");
119     } catch (UnsupportedOperationException expected) {
120     }
121     expectUnchanged();
122   }
123 
124   @MapFeature.Require(absent = SUPPORTS_PUT)
125   @CollectionSize.Require(absent = ZERO)
126   public void testPutAll_unsupportedAllPresent() {
127     try {
128       putAll(MinimalCollection.of(samples.e0));
129     } catch (UnsupportedOperationException tolerated) {
130     }
131     expectUnchanged();
132   }
133 
134   @MapFeature.Require({SUPPORTS_PUT,
135       ALLOWS_NULL_KEYS})
136   public void testPutAll_nullKeySupported() {
137     putAll(containsNullKey);
138     expectAdded(containsNullKey.get(0));
139   }
140 
141   @MapFeature.Require(value = SUPPORTS_PUT,
142       absent = ALLOWS_NULL_KEYS)
143   public void testPutAll_nullKeyUnsupported() {
144     try {
145       putAll(containsNullKey);
146       fail("putAll(containsNullKey) should throw");
147     } catch (NullPointerException expected) {
148     }
149     expectUnchanged();
150     expectNullKeyMissingWhenNullKeysUnsupported(
151         "Should not contain null key after unsupported " +
152         "putAll(containsNullKey)");
153   }
154 
155   @MapFeature.Require({SUPPORTS_PUT,
156       ALLOWS_NULL_VALUES})
157   public void testPutAll_nullValueSupported() {
158     putAll(containsNullValue);
159     expectAdded(containsNullValue.get(0));
160   }
161 
162   @MapFeature.Require(value = SUPPORTS_PUT,
163       absent = ALLOWS_NULL_VALUES)
164   public void testPutAll_nullValueUnsupported() {
165     try {
166       putAll(containsNullValue);
167       fail("putAll(containsNullValue) should throw");
168     } catch (NullPointerException expected) {
169     }
170     expectUnchanged();
171     expectNullValueMissingWhenNullValuesUnsupported(
172         "Should not contain null value after unsupported " +
173         "putAll(containsNullValue)");
174   }
175 
176   @MapFeature.Require(SUPPORTS_PUT)
177   public void testPutAll_nullCollectionReference() {
178     try {
179       getMap().putAll(null);
180       fail("putAll(null) should throw NullPointerException");
181     } catch (NullPointerException expected) {
182     }
183   }
184 
185   private Map<K, V> emptyMap() {
186     return Collections.emptyMap();
187   }
188 
189   private void putAll(Iterable<Entry<K, V>> entries) {
190     Map<K, V> map = new LinkedHashMap<K, V>();
191     for (Entry<K, V> entry : entries) {
192       map.put(entry.getKey(), entry.getValue());
193     }
194     getMap().putAll(map);
195   }
196 }
197